#include "server.h"
#include "router.h"
#include "tunnel.h"
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>



Server::Server (const Config& cfg) : _cfg(cfg) {
  TRACE
  _socket = socket(AF_INET, SOCK_STREAM, 0);
  abort_assert(_socket > 0);

  struct sockaddr_in addr = {0};
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(_cfg.port);
  abort_assert(0 == bind(_socket, (const sockaddr*)&addr, sizeof(addr)));
  abort_assert(0 == listen(_socket, 5));

  abort_assert(_rsa.setup_private(_cfg.rsa_key, strlen(_cfg.rsa_key)));
  _router = new Router(cfg);
}


Server::~Server () {
  TRACE
}


void Server::run () {
  TRACE
  _router->startup();
  struct sockaddr_in addr;
  for (;;) {
    socklen_t addrLen = sizeof(addr);
    auto socket = accept(_socket, (sockaddr*)&addr, &addrLen);
    if (socket < 0)
      break;
    u32 ipv4 = ntohl(addr.sin_addr.s_addr);
    u16 port = ntohs(addr.sin_port);

    auto tunnel = new Tunnel(this, _router, _rsa, socket, ipv4, port);
    addTunnel(tunnel);
    tunnel->startup();
  }
}


void Server::shutdown () {
  TRACE
  _router->shutdown();
  close(_socket);
}


void Server::addTunnel (Tunnel* tunnel) {
  TRACE
  std::lock_guard<std::mutex> lock {_mutex};
  _tunnels.push_back(&tunnel->joint);
  tunnel->retain();
}


void Server::delTunnel (Tunnel* tunnel) {
  TRACE
  std::lock_guard<std::mutex> lock {_mutex};
  tunnel->joint.detach();
  tunnel->release();
}